﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel.Composition;
using System.IO;
using System.Text.RegularExpressions;
using HtmlAgilityPack;

namespace Steve.UI.Extensions.Html
{
    [Export(typeof(ContentDataHandlerBase))]
    [ExportMetadata("Name", "Html")]
    public class HtmlContentDataHandler : ContentDataHandlerBase
    {
        static readonly Regex _regex = new Regex("((?:href|src)=['\"])(\\S+)(['\"])");

        const string ViewNameKey = "ViewName";
        const string MasterNameKey = "MasterName";
        const string DefaultEditViewName = "TextHtmlEdit";
        const string DefaultInputName = "text-html-content-data";

        [Import]
        public RewriterBase Rewriter { get; set; }
        [Import]
        public IHttpContextBaseBuilder ContextBuilder { get; set; }
        [Import]
        public ContentRepository ContentRepository { get; set; }

        protected internal virtual string GetText(Stream stream, bool ignoreLinks)
        {
            string html;

            using (var sr = new StreamReader(stream, Encoding.UTF8))
            {
                html = sr.ReadToEnd();
            }

            if (ignoreLinks) return html;
           
            var ctx = ContextBuilder.BuildCurrent();
            var baseUri = ctx == null ? (Uri)null : ctx.Request.Url;

            var rewriteHtml = _regex.Replace(html, (m) =>
            {
                Uri link;

                if (baseUri == null)
                    link = new Uri(m.Groups[2].Value);
                else
                    link = new Uri(baseUri, m.Groups[2].Value);

                var result = Rewriter.Rewrite(link);

                if (result != null && result.ToUrl != null)
                {
                    return m.Result("$1" + result.ToUrl.ToString() + "$3");
                }

                return m.Value;
            });

            return rewriteHtml;
        }

        public override ActionResult Render(Content content, ContentType contentType, bool raw)
        {
            if (content == null) throw new ArgumentNullException("content");
            if (contentType == null) throw new ArgumentNullException("contentType");

            var viewName = contentType.Parameters != null && contentType.Parameters.ContainsKey(ViewNameKey) ? contentType.Parameters[ViewNameKey] : contentType.ContentTypeName;
            var masterName = contentType.Parameters != null && contentType.Parameters.ContainsKey(MasterNameKey) ? contentType.Parameters[MasterNameKey] : null;
            var stream = ContentRepository.GetContentData(content.ContentDataId.Value);
            var text = GetText(stream, false);

            if (raw)
            {
                return new FileContentResult(Encoding.UTF8.GetBytes(text), content.FullMimeType + "; charset=utf-8");
            }

            var root = ContentRepository.GetContentDirectoryRoot();
            var nav = root.NavigateTo(content.Path);

            var result = new ViewResult();

            result.MasterName = masterName;
            result.ViewName = viewName;
            result.ViewData = new ViewDataDictionary();
            result.ViewData.Model = new HtmlContentDataHandlerRenderModel()
            {
                Content = content,
                Html = text,
                Directory = nav.DirectoryMatch,
            };

            return result;
        }

        public override ActionResult Edit(Content content, ContentType contentType)
        {
            if (content == null) throw new ArgumentNullException("content");
            if (contentType == null) throw new ArgumentNullException("contentType");

            var viewName = contentType.Parameters != null && contentType.Parameters.ContainsKey(ViewNameKey) ? contentType.Parameters[ViewNameKey] : DefaultEditViewName;

            var result = new PartialViewResult();

            result.ViewName = viewName;

            using (var sr = new StreamReader(ContentRepository.GetContentData(content.ContentDataId.Value), Encoding.UTF8))
            {
                var text = sr.ReadToEnd();

                result.ViewData.Model = new HtmlContentDataHandlerEditModel()
                {
                    Content = content,
                    Html = text,
                    InputName = DefaultInputName
                };
            }

            return result;
        }

        protected override ContentDataHandlerEditData GetEditData(ContentType contentType)
        {
            var ctx = ContextBuilder.BuildCurrent();
            var html = ctx.Request.Form[DefaultInputName];
            var bytes = Encoding.UTF8.GetBytes(html);

            return new ContentDataHandlerEditData()
            {
                MimeType = MimeType.Text,
                MimeSubtype = "html",
                Data = new MemoryStream(bytes)
            };
        }

        public override string ExtractText(Content content, ContentType contentType)
        {
            if (content == null) throw new ArgumentNullException("content");
            if (contentType == null) throw new ArgumentNullException("contentType");

            var stream = ContentRepository.GetContentData(content.ContentDataId.Value);
            var text = GetText(stream, true);

            var doc = new HtmlDocument();

            doc.LoadHtml(text);

            return doc.DocumentNode.InnerText;
        }
    }
}
